package cn.sxgan.gen.config;

import cn.sxgan.gen.model.GlobalDataSource;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Configuration
public class DataSourceConfig {
    
    private final Map<Object, Object> targetDataSources = new ConcurrentHashMap<>();
    private DataSource defaultDataSource;
    
    // 动态数据源引用
    private DynamicDataSource dynamicDataSource;
    
    private final static String DEFAULT_DATASOURCE_KEY = "zoey_mock_db";
    // 注入默认数据源配置
    @Bean
    @Primary
    @ConfigurationProperties("spring.datasource")
    public DataSourceProperties dataSourceProperties() {
        return new DataSourceProperties();
    }
    
    @Bean
    @Primary
    public DataSource dataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        // 设置默认数据源（从application.yml读取）
        defaultDataSource = buildDataSourceFromProperties();
        targetDataSources.put(DEFAULT_DATASOURCE_KEY, defaultDataSource);
        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(defaultDataSource);
        return dynamicDataSource;
    }
    
    // 动态添加数据源
    public void addDataSource(String key, DataSource dataSource) {
        targetDataSources.put(key, dataSource);
        // 刷新数据源
        ((DynamicDataSource) dataSource()).afterPropertiesSet();
    }
    
    // 移除数据源并关闭连接池
    public void removeDataSource(String key) {
        DataSource ds = (DataSource) targetDataSources.remove(key);
        if (ds instanceof DruidDataSource) {
            ((DruidDataSource) ds).close();
        }
        ((DynamicDataSource) dataSource()).afterPropertiesSet();
    }
    
    // 创建新数据源
    public DataSource createDataSource(String url, String username, String password, String driverClassName) {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        dataSource.setDriverClassName(driverClassName);
        // 设置重试参数
        // 设置连接获取重试参数
        dataSource.setConnectionErrorRetryAttempts(3);  // 获取连接重试次数
        dataSource.setBreakAfterAcquireFailure(true);            // 失败后中断获取
        
        // 设置连接验证重试参数
        dataSource.setValidationQuery("SELECT 1");
        dataSource.setTestWhileIdle(true);
        dataSource.setTestOnBorrow(true);
        dataSource.setTestOnReturn(false);
        
        // 设置重试等待时间（毫秒）
        dataSource.setTimeBetweenConnectErrorMillis(1000 * (long) Math.pow(2, 3));
        
        // 连接池大小配置（根据实际情况调整）
        dataSource.setInitialSize(3);
        dataSource.setMinIdle(3);
        dataSource.setMaxActive(20);
        dataSource.setMaxWait(60000);           // 从连接池获取连接的最大等待时间
        return dataSource;
    }
    
    private DataSource buildDataSourceFromProperties() {
        DataSourceProperties properties = dataSourceProperties();
        if (properties.getUrl() == null) {
            throw new IllegalStateException("无法从配置中读取数据源URL。请检查 spring.datasource.url 配置");
        }
        // 实现从application.yml读取默认配置
        return DataSourceBuilder.create()
                .url(properties.getUrl())
                .username(properties.getUsername())
                .password(properties.getPassword())
                .driverClassName(properties.getDriverClassName())
                .type(DruidDataSource.class)
                .build();
    }
    
    /**
     * 获取当前数据源相关信息
     *
     * @return
     */
    public String getDefaultDataSourceDriverName() {
        try {
            return defaultDataSource.getConnection().getMetaData().getDatabaseProductName();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 获取所有数据源信息
     *
     * @return 数据源信息列表
     */
    public List<GlobalDataSource> getAllDataSourceInfo() {
        List<GlobalDataSource> dataSourceInfos = new ArrayList<>();
        
        for (Map.Entry<Object, Object> entry : targetDataSources.entrySet()) {
            String key = entry.getKey().toString();
            DataSource ds = (DataSource) entry.getValue();
            GlobalDataSource info = new GlobalDataSource();
            info.setKey(key);
            
            // 公共信息获取
            if (ds instanceof DruidDataSource) {
                DruidDataSource druidDs = (DruidDataSource) ds;
                info.setUrl(druidDs.getUrl());
                info.setUsername(druidDs.getUsername());
                info.setDriverClassName(druidDs.getDriverClassName());
                info.setActiveCount(druidDs.getActiveCount());
                info.setIdleCount(druidDs.getPoolingCount() - druidDs.getActiveCount());
            } else {
                // 非Druid数据源处理
                try (Connection conn = ds.getConnection()) {
                    DatabaseMetaData metaData = conn.getMetaData();
                    info.setUrl(metaData.getURL());
                    info.setUsername(metaData.getUserName());
                    info.setDriverClassName(metaData.getDriverName());
                } catch (Exception e) {
                    // 错误处理
                    info.setUrl("Error: " + e.getMessage());
                }
            }
            
            // 获取数据库类型
            try (Connection conn = ds.getConnection()) {
                info.setDbType(conn.getMetaData().getDatabaseProductName());
            } catch (Exception e) {
                info.setDbType("Unknown");
            }
            
            dataSourceInfos.add(info);
        }
        return dataSourceInfos;
    }
    
    /**
     * 获取当前活动的数据源信息
     *
     * @return 当前活动数据源的详细信息
     */
    public GlobalDataSource getActiveDataSource() {
        // 确保 dynamicDataSource 已初始化
        if (dynamicDataSource == null) {
            dynamicDataSource = (DynamicDataSource) dataSource();
        }
        
        // 获取当前数据源 key（Object类型）
        Object lookupKeyObj = dynamicDataSource.determineCurrentLookupKey();
        String activeKey = "default";
        
        // 处理可能的key类型
        if (lookupKeyObj != null) {
            if (lookupKeyObj instanceof String) {
                activeKey = (String) lookupKeyObj;
            } else {
                // 非String类型转换为String表示
                activeKey = lookupKeyObj.toString();
            }
        }
        
        // 从注册的数据源映射中获取实际数据源
        DataSource activeDataSource = (DataSource) targetDataSources.get(activeKey);
        if (activeDataSource == null) {
            // 回退到默认数据源
            activeDataSource = defaultDataSource;
        }
        
        GlobalDataSource info = new GlobalDataSource();
        info.setKey(activeKey);
        
        try {
            // 使用单一连接获取所有元数据
            try (Connection conn = activeDataSource.getConnection()) {
                DatabaseMetaData metaData = conn.getMetaData();
                
                // 设置基础信息
                info.setUrl(metaData.getURL());
                info.setUsername(metaData.getUserName());
                info.setDriverClassName(metaData.getDriverName());
                info.setDbType(metaData.getDatabaseProductName());
            }
            
            // 单独处理Druid连接池信息
            if (activeDataSource instanceof DruidDataSource) {
                DruidDataSource druidDs = (DruidDataSource) activeDataSource;
                info.setActiveCount(druidDs.getActiveCount());
                info.setIdleCount(druidDs.getPoolingCount() - druidDs.getActiveCount());
            } else {
                // 非Druid数据源设置默认值
                info.setActiveCount(0);
                info.setIdleCount(0);
            }
            
        } catch (Exception e) {
            // 异常处理
            info.setDbType("获取失败: " + e.getMessage());
            info.setUrl("Error");
        }
        
        return info;
    }
}